Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • View renderedDownload


android/README.md v4.5.0-rc.5 (eee4a4d7) Text, 9.61 KB

Tc9d1d9# MeshChatX Android App

This directory contains the Android app build configuration using Chaquopy to embed the Python MeshChatX server.

Tc9d1d9## Architecture

The app uses a **WebView** to display the existing Vue.js frontend. The Python server runs in the background via Chaquopy and serves the web interface on Ta5d6ff`https://127.0.0.1:8000`.

Tc9d1d9## Build debug APK

Prerequisites:

Tff7b72- **JDK 17 or newer** (required by the Android Gradle Plugin used in this project). On distributions with multiple JDKs, point the build at JDK 17+ (for example Ta5d6ff`JAVA_HOME` for the Gradle invocation).
Tff7b72- **Android SDK** with API **34** platform and **Build-Tools 34** installed. Set Ta5d6ff`ANDROID_HOME` and Ta5d6ff`ANDROID_SDK_ROOT` to the SDK root (the same directory for both is fine).
Tff7b72- **Host build tools for wheel patching**: Ta5d6ff`patchelf`, Ta5d6ff`cmake`, Ta5d6ff`pkg-config`, Ta5d6ff`unzip`, and build essentials (Ta5d6ff`gcc`, Ta5d6ff`make`, headers). On Arch-based systems, install Ta5d6ff`patchelf cmake pkgconf base-devel rustup unzip`.
Tff7b72- **`android/vendor/`** must contain the Chaquopy vendor wheels (see [Tff7b72Updating Android Python ABI Wheels](Te6edf3#updating-android-python-abi-wheels-python-311)). The build fails fast if this directory is missing or incomplete.
Tff7b72- **MeshChatX Python sources** at the repository root (Ta5d6ff`meshchatx/`). The build syncs them into the app before compiling.

SDK licenses:

Tff7b72- Use **Command-line Tools** Ta5d6ff`sdkmanager`, not the legacy Ta5d6ff`tools/bin/sdkmanager` from old SDK layouts. The legacy tool loads JAXB classes that were removed from the JDK in Java 11, so running it on JDK 17+ fails with Ta5d6ff`NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema`.
Tff7b72- Install Command-line Tools if needed: download the package for your OS from [Tff7b72Android Studio command-line tools](Te6edf3https://developer.android.com/studio#command-tools), extract it so you have Ta5d6ff`cmdline-tools/latest/bin/sdkmanager` under Ta5d6ff`ANDROID_HOME` (the inner folder is often named Ta5d6ff`latest`; see Google’s layout for that zip).
Tff7b72- Accept licenses (writes under the SDK; use sudo if the SDK is root-owned):

Ta5d6ff```Ta5d6ffbash
yes Tb4b4b4| path/to/cmdline-tools/latest/bin/sdkmanager --licenses
Ta5d6ff```

Tff7b72- Install missing packages if the build still complains (platform 34, build-tools 34, etc.):

Ta5d6ff```Ta5d6ffbash
path/to/cmdline-tools/latest/bin/sdkmanager Ta5d6ff"platforms;android-34" Ta5d6ff"build-tools;34.0.0"
Ta5d6ff```

Build from the Ta5d6ff`android/` directory (default **slim** flavor, **universal** ABI packaging):

Ta5d6ff```Ta5d6ffbash
./gradlew :app:assembleSlimDebug
Ta5d6ff```

Debug APK example path:

Tff7b72- Ta5d6ff`app/build/outputs/apk/slim/debug/app-slim-debug.apk`

By default all ABIs are included in that single universal APK. To build only specific ABIs:

Ta5d6ff```Ta5d6ffbash
./gradlew :app:assembleSlimDebug -PmeshchatxAbisTff7b72=armeabi-v7a
./gradlew :app:assembleSlimDebug -PmeshchatxAbisTff7b72=arm64-v8a,x86_64
Ta5d6ff```

To emit **per-ABI split APKs** (and a universal split when Gradle enables it), set:

Ta5d6ff```Ta5d6ffbash
./gradlew :app:assembleSlimDebug -PmeshchatxAbiPackagingTff7b72=split
Ta5d6ff```

Same property accepts Ta5d6ff`MESHCHATX_ABI_PACKAGING`.

Tc9d1d9### Python bundle: `slim` vs `full` flavors

The Chaquopy layer packs Ta5d6ff`meshchatx/` into Ta5d6ff`assets/chaquopy/app.imy`. These are **Android product flavors** (separate Gradle variants):

| Flavor | Meaning |
|--------|--------|
| **`slim`** (default Ta5d6ff`isDefault`) | Smaller APK: sync omits Vue sources (Ta5d6ff`src/frontend`), bundled Reticulum HTML manual (Ta5d6ff`public/reticulum-docs-bundled`), RNode flasher static files, and **offline repository wheels** (Ta5d6ff`public/repository-server-bundled`). |
| **`full`** | Syncs the whole Ta5d6ff`meshchatx/` tree (Gradle runs Ta5d6ff`fetchRepositoryBundledWheels` first when bundled wheels are missing). Use when the APK must ship the offline repository mirror and bundled docs. |

Assemble the matching variant:

Ta5d6ff```Ta5d6ffbash
./gradlew :app:assembleSlimDebug -PmeshchatxAbisTff7b72=arm64-v8a
./gradlew :app:assembleFullDebug
./gradlew :app:assembleFullRelease
Ta5d6ff```

Tc9d1d9## Signing Release APKs (optional SourceStamp)

Build release APKs first:

Ta5d6ff```Ta5d6ffbash
./gradlew --no-daemon :app:assembleSlimRelease
Ta5d6ff```

Create a release signing key (one time):

Ta5d6ff```Ta5d6ffbash
mkdir -p android/keystore
keytool -genkeypair -v Tffea00\
-keystore android/keystore/meshchatx-release.jks Tffea00\
-alias meshchatx-release Tffea00\
-keyalg RSA Tffea00\
-keysize T79c0ff4096 Tffea00\
-validity T79c0ff9125
Ta5d6ff```

Optional: create a separate SourceStamp key (recommended if you use SourceStamp):

Ta5d6ff```Ta5d6ffbash
keytool -genkeypair -v Tffea00\
-keystore android/keystore/meshchatx-stamp.jks Tffea00\
-alias meshchatx-stamp Tffea00\
-keyalg RSA Tffea00\
-keysize T79c0ff4096 Tffea00\
-validity T79c0ff9125
Ta5d6ff```

Sign all Ta5d6ff`*-unsigned.apk` release artifacts:

Ta5d6ff```Ta5d6ffbash
Te6edf3ANDROID_HOMETff7b72=Ta5d6ff"Te6edf3$HOMETa5d6ff/Android/sdkTa5d6ff" Tffea00\
Te6edf3SIGNING_KEYSTORE_PATHTff7b72=android/keystore/meshchatx-release.jks Tffea00\
Te6edf3SIGNING_KEY_ALIASTff7b72=meshchatx-release Tffea00\
Te6edf3SIGNING_KEYSTORE_PASSWORDTff7b72=Ta5d6ff'<release-keystore-password>' Tffea00\
Te6edf3SIGNING_KEY_PASSWORDTff7b72=Ta5d6ff'<release-key-password>' Tffea00\
bash scripts/sign-android-apks.sh
Ta5d6ff```

Sign with SourceStamp enabled:

Ta5d6ff```Ta5d6ffbash
Te6edf3ANDROID_HOMETff7b72=Ta5d6ff"Te6edf3$HOMETa5d6ff/Android/sdkTa5d6ff" Tffea00\
Te6edf3SIGNING_KEYSTORE_PATHTff7b72=android/keystore/meshchatx-release.jks Tffea00\
Te6edf3SIGNING_KEY_ALIASTff7b72=meshchatx-release Tffea00\
Te6edf3SIGNING_KEYSTORE_PASSWORDTff7b72=Ta5d6ff'<release-keystore-password>' Tffea00\
Te6edf3SIGNING_KEY_PASSWORDTff7b72=Ta5d6ff'<release-key-password>' Tffea00\
Te6edf3ENABLE_SOURCESTAMPTff7b72=Tffa657true Tffea00\
Te6edf3SOURCESTAMP_KEYSTORE_PATHTff7b72=android/keystore/meshchatx-stamp.jks Tffea00\
Te6edf3SOURCESTAMP_KEY_ALIASTff7b72=meshchatx-stamp Tffea00\
Te6edf3SOURCESTAMP_KEYSTORE_PASSWORDTff7b72=Ta5d6ff'<stamp-keystore-password>' Tffea00\
Te6edf3SOURCESTAMP_KEY_PASSWORDTff7b72=Ta5d6ff'<stamp-key-password>' Tffea00\
bash scripts/sign-android-apks.sh
Ta5d6ff```

The helper script auto-detects the newest Android Build-Tools, runs Ta5d6ff`zipalign`, signs with Ta5d6ff`apksigner`, and verifies each output certificate/signature block.

Tc9d1d9## Updating Android Python ABI Wheels (Python 3.11)

Use this workflow when a dependency (for example Ta5d6ff`cryptography`) requires custom Android wheels for the ABIs listed in Ta5d6ff`app/build.gradle` (Ta5d6ff`ndk.abiFilters`).

For **`armeabi-v7a`**, Chaquopy usually has no prebuilt NumPy wheel; Ta5d6ff`scripts/build-android-wheels-local.sh` builds NumPy from source and must cache the official Ta5d6ff`chaquopy-openblas` wheel (handled in the script) and run with **`ANDROID_HOME`** pointing at an SDK that includes **Command-line Tools** and NDK **27.3.13750724** (Chaquopy’s Ta5d6ff`target/android-env.sh` installs the NDK via Ta5d6ff`sdkmanager` if missing).

Tff7b721. Build wheels in a Podman Python 3.11 container to avoid host Python mismatches:
Tff7b72- Use Ta5d6ff`docker.io/library/python:3.11-bookworm`.
Tff7b72- Mount project root to Ta5d6ff`/work` and Android SDK to Ta5d6ff`/opt/android-sdk`.
Tff7b72- Export Ta5d6ff`ANDROID_HOME` and Ta5d6ff`ANDROID_SDK_ROOT` to Ta5d6ff`/opt/android-sdk`.
Tff7b72- Example container entry:
Ta5d6ff`podman run --rm --network host -e ANDROID_HOME=/opt/android-sdk -e ANDROID_SDK_ROOT=/opt/android-sdk -v "/opt/android-sdk:/opt/android-sdk" -v "<repo>:/work" -w /work docker.io/library/python:3.11-bookworm bash`
Tff7b722. Keep custom Chaquopy recipes in Ta5d6ff`android/chaquopy-recipes/<package>-<major>/`:
Tff7b72- Define package/version in Ta5d6ff`meta.yaml`.
Tff7b72- Store source patches in Ta5d6ff`patches/`.
Tff7b723. Build the configured ABIs with Chaquopy Ta5d6ff`build-wheel.py` (via Ta5d6ff`scripts/build-android-wheels-local.sh`) and place final wheels in Ta5d6ff`android/vendor/`.
Tff7b724. Update Ta5d6ff`android/app/build.gradle` Ta5d6ff`pip` installs to the new pinned version.
Tff7b725. Rebuild with Ta5d6ff`./gradlew :app:assembleSlimDebug` (or Ta5d6ff`-PmeshchatxAbiPackaging=split` when you need per-ABI artifacts) and confirm the expected APK under Ta5d6ff`app/build/outputs/apk/`.

Local host build example (no shell startup files required):

Ta5d6ff```Ta5d6ffbash
Tffa657cd /path/to/reticulum-meshchatX
Te6edf3ANDROID_HOMETff7b72=Ta5d6ff"Te6edf3$HOMETa5d6ff/Android/sdkTa5d6ff" Tffea00\
Te6edf3ANDROID_SDK_ROOTTff7b72=Ta5d6ff"Te6edf3$HOMETa5d6ff/Android/sdkTa5d6ff" Tffea00\
Te6edf3PYTHON_BINTff7b72=Ta5d6ff"Tff7b72$(uv python find T79c0ff3.11Tff7b72)Ta5d6ff" Tffea00\
bash scripts/build-android-wheels-local.sh --abis armeabi-v7a
Ta5d6ff```

If Ta5d6ff`uv` does not have Python 3.11 yet, install it first:

Ta5d6ff```Ta5d6ffbash
uv python install T79c0ff3.11
Ta5d6ff```

If the wheel build fails with Ta5d6ff`No such file or directory: 'patchelf'`, install Ta5d6ff`patchelf` and re-run the same command.

Notes:
Tff7b72- For Rust-backed wheels (such as modern Ta5d6ff`cryptography`), build inside the container with Rust toolchain available.
Tff7b72- Keep recipe files and patches versioned; keep generated build artifacts untracked.

Tc9d1d9## Custom Recipes and Patches

This project keeps Android-specific Chaquopy recipes in Ta5d6ff`android/chaquopy-recipes/` to bridge gaps between desktop Python dependencies and Android wheel availability.

Tff7b72- Ta5d6ff`cryptography-46`
Tff7b72- Purpose: provide Android ABI wheels for Ta5d6ff`cryptography 46.0.7` for each ABI in the wheel script (for example Ta5d6ff`arm64-v8a`, Ta5d6ff`x86_64`, Ta5d6ff`armeabi-v7a`) because upstream Chaquopy index only provided older builds.
Tff7b72- Ta5d6ff`patches/openssl_no_legacy.patch`: disables OpenSSL legacy provider loading, which is unavailable in the bundled Android OpenSSL runtime.
Tff7b72- Ta5d6ff`patches/pyo3_no_interpreter.patch`: enables compatible Ta5d6ff`pyo3` ABI settings for Chaquopy Python 3.11 Android builds.

Tff7b72- Ta5d6ff`aiohttp-3.13`
Tff7b72- Purpose: align Android with desktop dependency line (Ta5d6ff`aiohttp 3.13.3`) by building fresh ABI wheels with Chaquopy.
Tff7b72- No source patch is required; recipe pins the newer upstream version for Android wheel generation.

Tff7b72- Ta5d6ff`psutil-7.2`
Tff7b72- Purpose: align Android with desktop dependency line (Ta5d6ff`psutil 7.2.2`) while preserving Android runtime behavior.
Tff7b72- Ta5d6ff`patches/chaquopy.patch`: treats Ta5d6ff`android` platform as Linux in psutil internals and forces a safe partition enumeration path because Ta5d6ff`/proc/filesystems` can be restricted by SELinux on some Android API levels.

Tff7b72- Ta5d6ff`bcrypt-5`
Tff7b72- Purpose: tracks attempted upgrade path to desktop-equivalent bcrypt.
Tff7b72- Status: currently not enabled in Android app dependencies; Ta5d6ff`bcrypt==3.1.7` remains pinned for stable APK builds.

Tc9d1d9## License

This directory is part of the main project licensing split:
Tff7b72- project-owned portions: 0BSD
Tff7b72- original upstream MeshChat portions: MIT

See [Ta5d6ff`../LICENSE`](../LICENSE) for full text and notices.


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────